﻿/*************************************************************************************
 * 工    具：  HK_NormalMapImporter
 * 
 * 描    述：  本工具用于在导入贴图时自动检测并设置法线贴图的 TextureType 为 Normal map。自动化设置如下：
 *            1.检查贴图文件名是否包含"_normal"、"_nrm"或"_n"等关键字。
 *            2.对贴图进行颜色特征采样，通过分析部分像素的颜色平均值，判断是否符合法线贴图的特征（R、G通道值接近0.5，B通道值接近1.0）。
 *            3.如果符合上述两个条件，则判定为法线贴图。
 *
 * 版    本：  V1.1
 * 作    者：  京产肠饭
 * 
 * 创    建：  2023/10/30  V1.0

 * 更    新：  2025/01/29  V1.1
 *            1.功能优化：移除了贴图分辨率的判定方法（原先的方式不准确），新增贴图颜色特征采样判定方法，实现通过贴图文件名关键字和颜色特征采用进行双重判断。
 * 
 * 链    接：  https://gitee.com/JingChanChangFan/hk_-unity-tools
*************************************************************************************/

using System.IO;
using UnityEditor;
using UnityEngine;

namespace HKTools
{
    [InitializeOnLoad]
    public class HK_NormalMapImporter : AssetPostprocessor
    {
        public static void ChangeState(bool isActive)
        {
            isEnabled = isActive;
        }

        static bool isEnabled = true;

        string[] keywords = new string[] { "_normal", "_nrm", "_n" };

        public void OnPreprocessTexture()
        {
            if (!isEnabled)
                return;

            TextureImporter importer = assetImporter as TextureImporter;

            importer.GetSourceTextureWidthAndHeight(out int width, out int height);

            // 规则1：文件名是否包含关键字
            bool isHasKeyword = IsHasKeyword(assetPath.ToLower());

            // 规则2：像素颜色特征（采样少量像素）
            bool isHasNormalColor = IsHasNormalColor(assetPath.ToLower(), width, height);

            // 如果是法线贴图，修改Texture Type为Normal map
            if (isHasKeyword && isHasNormalColor)
            {
                if (importer.textureType != TextureImporterType.NormalMap)
                {
                    importer.textureType = TextureImporterType.NormalMap;
                    HKDebug.Log("图片：" + assetPath + " 自动转换为 NormalMap");
                }
            }
        }

        bool IsHasNormalColor(string path, int width, int height)
        {
            // 如果贴图后缀正常的话
            if (path.EndsWith(".png") || path.EndsWith(".jpg") || path.EndsWith(".tga")
             || path.EndsWith(".psd") || path.EndsWith(".exr") || path.EndsWith(".tif"))
            {
                // 加载贴图
                Texture2D texture = new Texture2D(width / 2, height / 2);
                texture.LoadImage(File.ReadAllBytes(assetPath));

                // 采样部分像素
                int sampleCount = 100;
                float rSum = 0, gSum = 0, bSum = 0;
                for (int i = 0; i < sampleCount; i++)
                {
                    Color pixel = texture.GetPixel(
                        Random.Range(0, texture.width),
                        Random.Range(0, texture.height)
                    );
                    rSum += pixel.r;
                    gSum += pixel.g;
                    bSum += pixel.b;
                }

                // 计算平均值
                float rAvg = rSum / sampleCount;
                float gAvg = gSum / sampleCount;
                float bAvg = bSum / sampleCount;

                // 判断是否符合法线贴图特征
                if (Mathf.Abs(rAvg - 0.5f) < 0.1f &&
                    Mathf.Abs(gAvg - 0.5f) < 0.1f &&
                    Mathf.Abs(bAvg - 1.0f) < 0.1f)
                {
                    return true;
                }
            }

            return false;
        }

        bool IsHasKeyword(string path)
        {
            bool isHasKeyword = false;

            // 如果贴图后缀正常的话
            if (path.EndsWith(".png") || path.EndsWith(".jpg") || path.EndsWith(".tga")
             || path.EndsWith(".psd") || path.EndsWith(".exr") || path.EndsWith(".tif"))
            {
                path = path.Substring(0, path.Length - 4);

                // 判断路径中是否包含关键字
                for (int i = 0; i < keywords.Length; i++)
                {
                    if (path.Contains(keywords[i]))
                    {
                        isHasKeyword = true;
                        break; // 发现匹配后跳出循环
                    }
                }
            }

            return isHasKeyword;
        }
    }
}